/**
 * Copyright 2009 cestum.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.cestum.cave.ui.components.custom
{
import flash.events.Event;
import flashx.textLayout.elements.TextFlow;
import flashx.textLayout.formats.TextLayoutFormat;

import mx.core.mx_internal;
import mx.core.ScrollPolicy;
import mx.events.FlexEvent;

import spark.components.supportClasses.SkinnableTextBase;
import spark.events.TextOperationEvent;

use namespace mx_internal;

//--------------------------------------
//  Styles
//--------------------------------------

/**
 *  @copy spark.components.supportClasses.GroupBase#style:symbolColor
 *  
 *  @langversion 3.0
 *  @playerversion Flash 10
 *  @playerversion AIR 1.5
 *  @productversion Flex 4
 */ 
[Style(name="symbolColor", type="uint", format="Color", inherit="yes", theme="spark")]

/**
 *  @copy spark.components.Scroller#style.horizontalScrollPolicy
 * 
 *  @langversion 3.0
 *  @playerversion Flash 10
 *  @playerversion AIR 1.5
 *  @productversion Flex 4
 */ 
[Style(name="horizontalScrollPolicy", type="String", inherit="no", enumeration="off,on,auto")]

/**
 *  @copy spark.components.Scroller#style.verticalScrollPolicy
 * 
 *  @langversion 3.0
 *  @playerversion Flash 10
 *  @playerversion AIR 1.5
 *  @productversion Flex 4
 */ 
[Style(name="verticalScrollPolicy", type="String", inherit="no", enumeration="off,on,auto")]

//--------------------------------------
//  Skin states
//--------------------------------------

/**
 *  Normal State
 *  
 *  @langversion 3.0
 *  @playerversion Flash 10
 *  @playerversion AIR 1.5
 *  @productversion Flex 4
 */
[SkinState("normal")]

/**
 *  Disabled State
 *  
 *  @langversion 3.0
 *  @playerversion Flash 10
 *  @playerversion AIR 1.5
 *  @productversion Flex 4
 */
[SkinState("disabled")]

//--------------------------------------
//  Excluded APIs
//--------------------------------------

[Exclude(name="verticalAlign", kind="style")]
[Exclude(name="lineBreak", kind="style")]

//--------------------------------------
//  Other metadata
//--------------------------------------

[DefaultProperty("content")]

[DefaultTriggerEvent("change")]
public class CustomTextBase extends SkinnableTextBase
{
	public function CustomTextBase()
	{
		super();
	}
	
	//--------------------------------------------------------------------------
	//
	//  Variables
	//
	//--------------------------------------------------------------------------
	
	/**
	 *  @private
	 */
	private var horizontalScrollPolicyChanged:Boolean = false;
	
	/**
	 *  @private
	 */
	private var verticalScrollPolicyChanged:Boolean = false;
	
	//--------------------------------------------------------------------------
	//
	//  Overridden properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  text
	//----------------------------------
	
	[Bindable("change")]
	[Bindable("textChanged")]
	
	// Compiler will strip leading and trailing whitespace from text string.
	[CollapseWhiteSpace]
	
	/**
	 *  @private
	 */
	override public function set text(value:String):void
	{
		// Of 'text', 'textFlow', and 'content', the last one set wins.
		
		super.text = value;
		
		// Trigger bindings to textChanged.
		dispatchEvent(new Event("textChanged"));        
	}
	
	//--------------------------------------------------------------------------
	//
	//  Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  content
	//----------------------------------
	
	/**
	 *  @private
	 *  This metadata tells the MXML compiler to disable some of its default
	 *  interpretation of the value specified for the 'content' property.
	 *  Normally, for properties of type Object, it assumes that things
	 *  looking like numbers are numbers and things looking like arrays
	 *  are arrays. But <content>1</content> should generate code to set the
	 *  content to  the String "1", not the int 1, and <content>[1]</content>
	 *  should set it to the String "[1]", not the Array [ 1 ].
	 *  However, {...} continues to be interpreted as a databinding
	 *  expression, and @Resource(...), @Embed(...), etc.
	 *  as compiler directives.
	 *  Similar metadata on TLF classes causes the same rules to apply
	 *  within <p>, <span>, etc.
	 */
	[RichTextContent]
	
	/**
	 *  This property is intended for use in MXML at compile time;
	 *  to get or set rich text content at runtime,
	 *  use the <code>textFlow</code> property instead. Adobe recommends using 
	 *  <code>textFlow</code> property to get and set rich text content at runtime,
	 *  because it is strongly typed as a TextFlow rather than as an Object.
	 *  A TextFlow is the canonical representation 
	 *  for rich text content in the Text Layout Framework.
	 *
	 *  <p>The <code>content</code> property is the default property
	 *  for TextArea, so that you can write MXML such as
	 *  <pre>
	 *  &lt;s:TextArea&gt;Hello &lt;s:span fontWeight="bold"/&gt;World&lt;/s:span&gt;&lt;/s:TextArea&gt;
	 *  </pre>
	 *  and have the String and SpanElement that you specify
	 *  as the content be used to create a TextFlow.</p>
	 *
	 *  <p>This property is typed as Object because you can set it to
	 *  to a String, a FlowElement, or an Array of Strings and FlowElements.
	 *  In the example above, the content is
	 *  a 2-element array. The first array element is the String
	 *  "Hello". The second array element is a SpanElement object with the text
	 *  "World" in boldface.</p>
	 * 
	 *  <p>No matter how you specify the content, the content is converted
	 *  to a TextFlow object. When you get the value of this property, you get
	 *  the resulting TextFlow object.</p>
	 * 
	 *  <p></p>
	 * 
	 *  @langversion 3.0
	 *  @playerversion Flash 10
	 *  @playerversion AIR 1.5
	 *  @productversion Flex 4
	 */
	public function get content():Object
	{
		return textFlow;
	}
	
	/**
	 *  @private
	 */   
	public function set content(value:Object):void
	{
		// Of 'text', 'textFlow', and 'content', the last one set wins.
		
		setContent(value);
	}
	
	//----------------------------------
	//  textFlow
	//----------------------------------
	
	// Note:
	// The 'textFlow' property is not bindable because you can't share a 
	// TextFlow between two editable components, due to the way that FTE and 
	// TLF work.
	
	/**
	 *  @copy spark.components.RichEditableText#textFlow
	 *  
	 *  @langversion 3.0
	 *  @playerversion Flash 10
	 *  @playerversion AIR 1.5
	 *  @productversion Flex 4
	 */
	public function get textFlow():TextFlow
	{
		return getTextFlow();
	}
	
	/**
	 *  @private
	 */
	public function set textFlow(value:TextFlow):void
	{
		// Of 'text', 'textFlow', and 'content', the last one set wins.
		
		setTextFlow(value);
	}
	
	//----------------------------------
	//  heightInLines
	//----------------------------------
	
	/**
	 *  @copy spark.components.RichEditableText#heightInLines
	 *  
	 *  @langversion 3.0
	 *  @playerversion Flash 10
	 *  @playerversion AIR 1.5
	 *  @productversion Flex 4
	 */
	public function get heightInLines():Number
	{
		return getHeightInLines();
	}
	
	/**
	 *  @private
	 */
	public function set heightInLines(value:Number):void
	{
		setHeightInLines(value);
	}
	
	//----------------------------------
	//  scroller
	//----------------------------------
	
	[SkinPart(required="false")]
	
	//----------------------------------
	//  widthInChars
	//----------------------------------
	
	/**
	 *  @copy spark.components.RichEditableText#widthInChars
	 *  
	 *  @langversion 3.0
	 *  @playerversion Flash 10
	 *  @playerversion AIR 1.5
	 *  @productversion Flex 4
	 */
	public function get widthInChars():Number
	{
		return getWidthInChars();
	}
	
	/**
	 *  @private
	 */
	public function set widthInChars(value:Number):void
	{
		setWidthInChars(value);
	}
	
	//--------------------------------------------------------------------------
	//
	//  Overridden methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 *  @private
	 */
	override public function styleChanged(styleProp:String):void
	{
		var allStyles:Boolean = (styleProp == null || styleProp == "styleName");
		super.styleChanged(styleProp);
		
		if (allStyles || styleProp == "horizontalScrollPolicy")
		{
			horizontalScrollPolicyChanged = true;
			invalidateProperties();
		}
		if (allStyles || styleProp == "verticalScrollPolicy")
		{
			verticalScrollPolicyChanged = true;
			invalidateProperties();
		}
	}
	
	/**
	 *  @private
	 *  Pushes various TextInput properties down into the RichEditableText. 
	 */
	override protected function commitProperties():void
	{
		super.commitProperties();
		
//		if (horizontalScrollPolicyChanged)
//		{
//			if (scroller)
//				scroller.setStyle("horizontalScrollPolicy", getStyle("horizontalScrollPolicy"));
//			horizontalScrollPolicyChanged = false;
//		}
//		
//		if (verticalScrollPolicyChanged)
//		{
//			if (scroller)
//				scroller.setStyle("verticalScrollPolicy", getStyle("verticalScrollPolicy"));
//			verticalScrollPolicyChanged = false;
//		}
	}
	
	/**
	 *  @private
	 */
	override protected function partAdded(partName:String, instance:Object):void
	{
		super.partAdded(partName, instance);
		
		if (instance == textDisplay)
		{
			// In default.css, the TextArea selector has a declaration
			// for lineBreak which sets it to "toFit".
			
			// The skin is loaded after the intial properties have been
			// set so these wipe out explicit sets.
			textDisplay.multiline = true;
		}
		
//		// The scroller, between textDisplay and this in the chain, should not 
//		// getFocus.
//		if (instance == scroller)
//		{
//			scroller.focusEnabled = false;
//			
//			// TLF does scrolling in real numbers.  If the scroller doesn't
//			// round to ints then the sets of verticalScrollPosition and
//			// horizontalScrollPosition will be no-ops which is desirable.
//			if (scroller.horizontalScrollBar)
//				scroller.horizontalScrollBar.snapInterval = 0;
//			if (scroller.verticalScrollBar)
//				scroller.verticalScrollBar.snapInterval = 0;
//		}
	}
	
	//--------------------------------------------------------------------------
	//
	//  Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 *  @copy spark.components.RichEditableText#getFormatOfRange()
	 *  
	 *  @langversion 3.0
	 *  @playerversion Flash 10
	 *  @playerversion AIR 1.5
	 *  @productversion Flex 4
	 */
	public function getFormatOfRange(requestedFormats:Vector.<String>=null,
									 anchorPosition:int=-1,
									 activePosition:int=-1):TextLayoutFormat
	{
		if (!textDisplay)
			return null;
		
		return textDisplay.getFormatOfRange(requestedFormats, anchorPosition, 
			activePosition);
	}
	
	/**
	 *  @copy spark.components.RichEditableText#setFormatOfRange()
	 *  
	 *  @langversion 3.0
	 *  @playerversion Flash 10
	 *  @playerversion AIR 1.5
	 *  @productversion Flex 4
	 */
	public function setFormatOfRange(format:TextLayoutFormat,
									 anchorPosition:int=-1, 
									 activePosition:int=-1):void
	{
		if (!textDisplay)
			return;
		
		textDisplay.setFormatOfRange(format, anchorPosition, activePosition);
	}
	
	/**
	 *  @copy spark.components.RichEditableText#scrollToRange()
	 *  
	 *  @langversion 3.0
	 *  @playerversion Flash 10
	 *  @playerversion AIR 1.5
	 *  @productversion Flex 4
	 */
	public function scrollToRange(anchorPosition:int = 0,
								  activePosition:int = int.MAX_VALUE):void
	{
		if (!textDisplay)
			return;
		
		textDisplay.scrollToRange(anchorPosition, activePosition);
	}

}
}